/*
 *
 * Copyright (C) 2017 Cafe Beverage. All rights reserved.
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU licence.
 *
 * A copy of the licence is included with the program, and can also be obtained
 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <fcntl.h>

struct ioctl_buffer {
	unsigned long request;
	void *ptr;
};

struct ioctl_buffer *ioctls = NULL;
int ioctl_count = 0;

struct mmap_buffer {
	uint64_t gpu_va;
	uint64_t length;
	void *buffer;
};

struct mmap_buffer *mmaps = NULL;
int mmap_count = 0;

int main(int argc, const char **argv)
{
	if (argc != 3) {
		printf("Usage: ./replay ioctl.bin memory.bin\n");
		return 1;
	}

	FILE *fp;

	/* Read and decode ioctls in a blocky way */
	fp = fopen(argv[1], "rb");
	unsigned long request;

	while(fread(&request, 1, sizeof(request), fp) == sizeof(request)) {
		ioctls = realloc(ioctls, sizeof(struct ioctl_buffer) * (++ioctl_count));
		struct ioctl_buffer* buffer = &ioctls[ioctl_count - 1];

		buffer->request = request;
		
		size_t s = _IOC_SIZE(buffer->request);

		void *arg = malloc(s);
		printf("malloc(%d) = %p\n", s, arg);
		buffer->ptr = arg;
		fread(arg, 1, s, fp);

		printf("Request: %lx\n", buffer->request);
	}
	
	fclose(fp);

#if 0
	/* Read and decode memory */
	fp = fopen(argv[2], "rb");

	uint64_t gpu_va;
	while(fread(&gpu_va, 1, sizeof(gpu_va), fp) == sizeof(gpu_va)) {
		mmaps = realloc(mmaps, sizeof(struct mmap_buffer) * (++mmap_count));
		struct mmap_buffer buffer = mmaps[mmap_count - 1];

		buffer->gpu_va = gpu_va;
		fread(&buffer->length, 1, sizeof(buffer->length), fp);

		buffer->buffer = malloc(buffer->length);
		fread(buffer->buffer, 1, buffer->length, fp);
	}
#endif

	/* Open a context with the kernel */
	int fd = open("/dev/mali0", O_RDWR | O_CLOEXEC);

	/* Walk the ioctl tree */
	for(int i = 0; i < ioctl_count; ++i) {
		struct ioctl_buffer io = ioctls[i];
		printf("(%lx, %p)\n", io.request, io.ptr);
		ioctl(fd, io.request, io.ptr);
	}

	/* TODO: Put in memory at the right places */
	return 1;
}
